package master

import (
	"context"
	"encoding/json"
	"fmt"
	"study-crontab/crontab/common"
	"time"

	clientv3 "go.etcd.io/etcd/client/v3"
)

type JobMgr struct {
	client *clientv3.Client
	kv     clientv3.KV
	lease  clientv3.Lease
}

//保存任务
func (m *JobMgr) SaveJob(job *common.Job) (oldJob *common.Job, err error) {
	jobKey := common.JOB_SAVE_DIR + job.Name
	var jobValue []byte
	if jobValue, err = json.Marshal(*job); err != nil {
		return nil, err
	}
	//保存到etcd
	putResp, err := m.kv.Put(context.TODO(), jobKey, string(jobValue), clientv3.WithPrevKV())
	if err != nil {
		return nil, err
	}
	if putResp.PrevKv != nil {
		oldJobObj := common.Job{}
		err = json.Unmarshal(putResp.PrevKv.Value, &oldJobObj)
		if err != nil {
			err = nil
			return
		}
		oldJob = &oldJobObj
	}
	return
}

//删除任务
func (m *JobMgr) DeleteJob(name string) (oldJob *common.Job, err error) {
	jobKey := common.JOB_SAVE_DIR + name

	//etcd中删除
	deleteResp, err := m.kv.Delete(context.TODO(), jobKey, clientv3.WithPrevKV())
	if err != nil {
		return nil, err
	}

	if len(deleteResp.PrevKvs) != 0 {
		oldJobObj := common.Job{}

		err = json.Unmarshal(deleteResp.PrevKvs[0].Value, &oldJobObj)
		if err != nil {
			err = nil
			return
		}
		oldJob = &oldJobObj
	}
	return
}

//获取所有任务
func (m *JobMgr) ListJob() (jobList []*common.Job, err error) {
	jobKey := common.JOB_SAVE_DIR

	//etcd中目录下所有任务
	getResp, err := m.kv.Get(context.TODO(), jobKey, clientv3.WithPrefix())
	if err != nil {
		return nil, err
	}
	jobList = make([]*common.Job, 0)
	//遍历所有任务
	for _, v := range getResp.Kvs {
		jobObj := &common.Job{}
		err = json.Unmarshal(v.Value, jobObj)
		if err != nil {
			err = nil
			continue
		}
		jobList = append(jobList, jobObj)
	}

	return
}

//杀死任务
func (m *JobMgr) KillJob(name string) (err error) {
	jobKey := common.JOB_KILLER_DIR + name

	//更新key=/cron/killer/任务名
	//让worker监听到一次put操作，创建一个租约让其自动过期
	grantResp, err := m.lease.Grant(context.TODO(), 1)
	if err != nil {
		return err
	}

	//租约id
	leaseId := grantResp.ID

	//设置killer标记
	_, err = m.kv.Put(context.TODO(), jobKey, "", clientv3.WithLease(leaseId))
	if err != nil {
		return err
	}

	return
}

var G_jobMgr *JobMgr

// NewJobMgr 初始化管理器
func NewJobMgr() error {
	config := clientv3.Config{
		Endpoints:   G_config.EtcdEndpoints,
		DialTimeout: time.Duration(G_config.EtcdDialTimeout) * time.Millisecond,
	}

	//建立连接
	client, err := clientv3.New(config)
	if err != nil {
		fmt.Println("etcd连接失败")
		return err
	}

	kv := clientv3.NewKV(client)
	lease := clientv3.NewLease(client)

	G_jobMgr = &JobMgr{
		client: client,
		kv:     kv,
		lease:  lease,
	}
	return nil
}
